﻿using System;
using System.Net;
using System.IO;

namespace LinkDownloader.Core
{

    public class CookieManager
    {        

        public static CookieCollection GetCookie(string url)
        {

            CookieCollection ret = new CookieCollection();
            url = url.Remove(0, 7);

            string baseUrl = ((url.IndexOf("/") > 0) ? url.Substring(0, url.IndexOf("/")) : url) + "/";
            string domain = baseUrl;

            domain = domain.Substring(0, domain.LastIndexOf('.'));
            while (domain.IndexOf('.') > -1)
            {
                domain = domain.Substring(domain.IndexOf('.') + 1);
            }

            FileInfo[] fis = SearchCookies(domain);
            foreach (FileInfo fi in fis)
            {

                CookieStruct[] cs = ReadCookie(fi.FullName);
                foreach (CookieStruct c in cs)
                {
                    if (baseUrl.EndsWith(c.Domain) && c.ExpirationDate > DateTime.Now)
                    {
                        Cookie nc = new Cookie(c.VarName, c.VarValue);
                        nc.Expires = c.ExpirationDate;
                        nc.Domain = c.Domain;
                        ret.Add(nc);
                    }
                }

            }

            return ret;

        }

        /// <summary>
        /// Searches for all the cookies in the current environment of the given domain.
        /// </summary>
        /// <param name="domain">The associated domain to be looked for.</param>
        /// <returns>Set of cookie files found; can be empty.</returns>
        private static FileInfo[] SearchCookies(string domain)
        {

            string path = Environment.GetFolderPath(Environment.SpecialFolder.Cookies);
            DirectoryInfo di = new DirectoryInfo(path);
            FileInfo[] fis = di.GetFiles(string.Format("*@{0}[*.txt", domain));

            di = new DirectoryInfo(path + "//Low");
            FileInfo[] fisLow = di.GetFiles(string.Format("*@{0}[*.txt", domain));
            
            FileInfo[] ret = new FileInfo[fis.Length + fisLow.Length];
            fis.CopyTo(ret, 0);
            fisLow.CopyTo(ret, fis.Length);
            return ret;

        }

        /// <summary>
        /// Reads a cookie given by the path.
        /// </summary>
        /// <param name="fn">Filename of the cookie to be read.</param>
        /// <returns>The contents that were read in stored as a CookieStruct.</returns>
        private static CookieStruct[] ReadCookie(string fn)
        {

            StreamReader sr = new StreamReader(fn);
            string cookie = sr.ReadToEnd();
            sr.Close();

            string[] data = cookie.Split('\n');
            int cookieNum = data.Length / 9;
            CookieStruct[] ret = new CookieStruct[cookieNum];

            for (int i = 0; i < cookieNum; i++)
            {
                int bline = i * 9;
                ret[i] = new CookieStruct();
                ret[i].VarName = data[bline];
                ret[i].VarValue = data[bline + 1];
                ret[i].Domain = data[bline + 2];
                ret[i].Flags = Convert.ToInt32(data[bline + 3]);
                long l = Convert.ToInt64(data[bline + 4]);
                l += Convert.ToInt64(data[bline + 5]) << 32;
                ret[i].ExpirationDate = DateTime.FromFileTime(l);
                l = Convert.ToInt64(data[bline + 6]);
                l += Convert.ToInt64(data[bline + 7]) << 32;
                ret[i].CreationDate = DateTime.FromFileTime(l);
            }

            return ret;

        }

    }

    internal struct CookieStruct
    {

        //1 The Variable Name
        //2 The Value for the Variable
        //3 The Website of the Cookie’s Owner
        //4 Optional Flags
        //5 The Most Significant Integer for Expired Time, in FILETIME Format
        //6 The Least Significant Integer for Expired Time, in FILETIME Format
        //7 The Most Significant Integer for Creation Time, in FILETIME Format
        //8 The Least Significant Integer for Creation Time, in FILETIME Format
        //9 The Cookie Record Delimiter (a * character)

        public string VarName;
        public string VarValue;
        public string Domain;
        public int Flags;
        public DateTime ExpirationDate;
        public DateTime CreationDate;

    }

}
